home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / channel.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-04  |  41.6 KB  |  1,783 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. #include <gtk/gtk.h>
  25.  
  26. #include "apptypes.h"
  27.  
  28. #include "appenv.h"
  29. #include "channel.h"
  30. #include "drawable.h"
  31. #include "gdisplay.h"
  32. #include "gimage_mask.h"
  33. #include "layer.h"
  34. #include "paint_funcs.h"
  35. #include "parasitelist.h"
  36. #include "temp_buf.h"
  37. #include "undo.h"
  38. #include "gimpsignal.h"
  39. #include "gimppreviewcache.h"
  40.  
  41. #include "channel_pvt.h"
  42. #include "tile.h"
  43.  
  44. #include "gimplut.h"
  45. #include "lut_funcs.h"
  46.  
  47. #include "libgimp/gimpmath.h"
  48.  
  49. #include "libgimp/gimpintl.h"
  50.  
  51.  
  52. enum {
  53.   REMOVED,
  54.   LAST_SIGNAL
  55. };
  56.  
  57. static void gimp_channel_class_init (GimpChannelClass *klass);
  58. static void gimp_channel_init       (GimpChannel      *channel);
  59. static void gimp_channel_destroy    (GtkObject        *object);
  60.  
  61. static TempBuf * channel_preview_private (Channel *channel,
  62.                       gint     width,
  63.                       gint     height);
  64.  
  65. static guint channel_signals[LAST_SIGNAL] = { 0 };
  66.  
  67. static GimpDrawableClass *parent_class = NULL;
  68.  
  69. GtkType
  70. gimp_channel_get_type ()
  71. {
  72.   static GtkType channel_type = 0;
  73.  
  74.   if (!channel_type)
  75.     {
  76.       GtkTypeInfo channel_info =
  77.       {
  78.     "GimpChannel",
  79.     sizeof (GimpChannel),
  80.     sizeof (GimpChannelClass),
  81.     (GtkClassInitFunc) gimp_channel_class_init,
  82.     (GtkObjectInitFunc) gimp_channel_init,
  83.         /* reserved_1 */ NULL,
  84.     /* reserved_2 */ NULL,
  85.     (GtkClassInitFunc) NULL,
  86.       };
  87.  
  88.       channel_type = gtk_type_unique (gimp_drawable_get_type (), &channel_info);
  89.     }
  90.  
  91.   return channel_type;
  92. }
  93.  
  94. static void
  95. gimp_channel_class_init (GimpChannelClass *class)
  96. {
  97.   GtkObjectClass *object_class;
  98.  
  99.   object_class = (GtkObjectClass*) class;
  100.   parent_class = gtk_type_class (gimp_drawable_get_type ());
  101.  
  102.   channel_signals[REMOVED] =
  103.       gimp_signal_new ("removed",
  104.                0, object_class->type, 0, gimp_sigtype_void);
  105.  
  106.   gtk_object_class_add_signals (object_class, channel_signals, LAST_SIGNAL);
  107.  
  108.   object_class->destroy = gimp_channel_destroy;
  109. }
  110.  
  111. static void
  112. gimp_channel_init (GimpChannel *channel)
  113. {
  114. }
  115.  
  116. /**************************/
  117. /*  Function definitions  */
  118. /**************************/
  119.  
  120. static void
  121. channel_validate (TileManager *tm,
  122.           Tile        *tile)
  123. {
  124.   /*  Set the contents of the tile to empty  */
  125.   memset (tile_data_pointer (tile, 0, 0), 
  126.       TRANSPARENT_OPACITY, tile_size (tile));
  127. }
  128.  
  129. Channel *
  130. channel_new (GimpImage *gimage,
  131.          gint       width,
  132.          gint       height,
  133.          gchar     *name,
  134.          gint       opacity,
  135.          guchar    *col)
  136. {
  137.   Channel * channel;
  138.   gint i;
  139.  
  140.   channel = gtk_type_new (gimp_channel_get_type ());
  141.  
  142.   gimp_drawable_configure (GIMP_DRAWABLE (channel), 
  143.                gimage, width, height, GRAY_GIMAGE, name);
  144.  
  145.   /*  set the channel color and opacity  */
  146.   for (i = 0; i < 3; i++)
  147.     channel->col[i] = col[i];
  148.  
  149.   channel->opacity     = opacity;
  150.   channel->show_masked = TRUE;
  151.  
  152.   /*  selection mask variables  */
  153.   channel->empty          = TRUE;
  154.   channel->segs_in        = NULL;
  155.   channel->segs_out       = NULL;
  156.   channel->num_segs_in    = 0;
  157.   channel->num_segs_out   = 0;
  158.   channel->bounds_known   = TRUE;
  159.   channel->boundary_known = TRUE;
  160.   channel->x1             = 0;
  161.   channel->y1             = 0;
  162.   channel->x2             = width;
  163.   channel->y2             = height;
  164.  
  165.   return channel;
  166. }
  167.  
  168. Channel *
  169. channel_ref (Channel *channel)
  170. {
  171.   gtk_object_ref  (GTK_OBJECT (channel));
  172.   gtk_object_sink (GTK_OBJECT (channel));
  173.  
  174.   return channel;
  175. }
  176.  
  177. void
  178. channel_unref (Channel *channel)
  179. {
  180.   gtk_object_unref (GTK_OBJECT (channel));
  181. }
  182.  
  183. Channel *
  184. channel_copy (Channel *channel)
  185. {
  186.   gchar *channel_name;
  187.   Channel *new_channel;
  188.   PixelRegion srcPR, destPR;
  189.   gchar *ext;
  190.   gint number;
  191.   gchar *name;
  192.   gint len;
  193.  
  194.   /*  formulate the new channel name  */
  195.   name = channel_get_name (channel);
  196.   ext = strrchr (name, '#');
  197.   len = strlen (_("copy"));
  198.   if ((strlen (name) >= len &&
  199.        strcmp (&name[strlen (name) - len], _("copy")) == 0) ||
  200.       (ext && (number = atoi (ext + 1)) > 0 && 
  201.        ((int)(log10 (number) + 1)) == strlen (ext + 1)))
  202.     /* don't have redundant "copy"s */
  203.     channel_name = g_strdup (name);
  204.   else
  205.     channel_name = g_strdup_printf (_("%s copy"), name);
  206.  
  207.   /*  allocate a new channel object  */
  208.   new_channel = channel_new (GIMP_DRAWABLE (channel)->gimage, 
  209.                  GIMP_DRAWABLE (channel)->width, 
  210.                  GIMP_DRAWABLE (channel)->height, 
  211.                  channel_name, channel->opacity, channel->col);
  212.   GIMP_DRAWABLE (new_channel)->visible = GIMP_DRAWABLE (channel)->visible;
  213.   new_channel->show_masked = channel->show_masked;
  214.  
  215.   /*  copy the contents across channels  */
  216.   pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles, 0, 0, 
  217.              GIMP_DRAWABLE (channel)->width, 
  218.              GIMP_DRAWABLE (channel)->height, FALSE);
  219.   pixel_region_init (&destPR, GIMP_DRAWABLE (new_channel)->tiles,
  220.              0, 0,
  221.              GIMP_DRAWABLE (channel)->width,
  222.              GIMP_DRAWABLE (channel)->height, TRUE);
  223.   copy_region (&srcPR, &destPR);
  224.  
  225.   /* copy the parasites */
  226.   GIMP_DRAWABLE (new_channel)->parasites 
  227.     = parasite_list_copy (GIMP_DRAWABLE (channel)->parasites);
  228.  
  229.   /*  free up the channel_name memory  */
  230.   g_free (channel_name);
  231.  
  232.   return new_channel;
  233. }
  234.  
  235. void
  236. channel_set_name (Channel *channel,
  237.           gchar   *name)
  238. {
  239.   gimp_drawable_set_name (GIMP_DRAWABLE (channel), name);
  240. }
  241.  
  242. gchar *
  243. channel_get_name (Channel *channel)
  244. {
  245.   return gimp_drawable_get_name (GIMP_DRAWABLE (channel));
  246. }
  247.  
  248. void 
  249. channel_set_color (Channel *channel,
  250.            guchar  *color)
  251. {
  252.   gint i;
  253.  
  254.   if (color)
  255.     {  
  256.       for (i = 0; i < 3; i++)
  257.     channel->col[i] = color[i];
  258.     }
  259. }
  260.  
  261. guchar *
  262. channel_get_color (Channel *channel)
  263. {
  264.   return (GIMP_CHANNEL (channel)->col); 
  265. }
  266.  
  267. int
  268. channel_get_opacity (Channel *channel)
  269.   return channel->opacity;
  270. }
  271.  
  272. void 
  273. channel_set_opacity (Channel *channel,
  274.              gint     opacity)
  275. {
  276.   if (opacity >=0 && opacity <= 100)
  277.     channel->opacity = (gint) (opacity * 255) / 100;
  278. }
  279.  
  280. Channel *
  281. channel_get_ID (gint ID)
  282. {
  283.   GimpDrawable *drawable;
  284.  
  285.   drawable = drawable_get_ID (ID);
  286.   if (drawable && GIMP_IS_CHANNEL (drawable)) 
  287.     return GIMP_CHANNEL (drawable);
  288.   else
  289.     return NULL;
  290. }
  291.  
  292. void
  293. channel_delete (Channel *channel)
  294. {
  295.   /*  Channels are normally deleted by removing them from the associated
  296.       image. The only case where channel_delete() is useful is if you want
  297.       to remove a floating channel object that has not been added to an
  298.       image yet. We use gtk_object_sink() for this reason here.
  299.    */
  300.   gtk_object_sink (GTK_OBJECT (channel));
  301. }
  302.  
  303. static void
  304. gimp_channel_destroy (GtkObject *object)
  305. {
  306.   GimpChannel *channel;
  307.  
  308.   g_return_if_fail (object != NULL);
  309.   g_return_if_fail (GIMP_IS_CHANNEL (object));
  310.  
  311.   channel = GIMP_CHANNEL (object);
  312.  
  313.   /* free the segments?  */
  314.   if (channel->segs_in)
  315.     g_free (channel->segs_in);
  316.   if (channel->segs_out)
  317.     g_free (channel->segs_out);
  318.  
  319.   if (GTK_OBJECT_CLASS (parent_class)->destroy)
  320.     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
  321.   
  322. }
  323.  
  324. /* The removed signal is sent out when the channel is no longer
  325.  * associcated with an image.  It's needed because channels aren't
  326.  * destroyed immediately, but kept around for undo purposes.  Connect
  327.  * to the removed signal to update bits of UI that are tied to a
  328.  * particular layer. */
  329. void
  330. channel_removed (Channel  *channel,
  331.          gpointer  data)
  332. {
  333.   g_return_if_fail (channel != NULL);
  334.   g_return_if_fail (GIMP_IS_CHANNEL (channel));
  335.  
  336.   gtk_signal_emit (GTK_OBJECT (channel), channel_signals[REMOVED]);
  337. }
  338.  
  339.  
  340. void
  341. channel_scale (Channel *channel,
  342.            gint     new_width,
  343.            gint     new_height)
  344. {
  345.   PixelRegion srcPR, destPR;
  346.   TileManager *new_tiles;
  347.  
  348.   if (new_width == 0 || new_height == 0)
  349.     return;
  350.  
  351.   /*  Update the old channel position  */
  352.   drawable_update (GIMP_DRAWABLE (channel),
  353.            0, 0,
  354.            GIMP_DRAWABLE (channel)->width,
  355.            GIMP_DRAWABLE (channel)->height);
  356.  
  357.   /*  Configure the pixel regions  */
  358.   pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
  359.              0, 0,
  360.              GIMP_DRAWABLE (channel)->width,
  361.              GIMP_DRAWABLE (channel)->height, FALSE);
  362.  
  363.   /*  Allocate the new channel, configure dest region  */
  364.   new_tiles = tile_manager_new (new_width, new_height, 1);
  365.   pixel_region_init (&destPR, new_tiles, 0, 0, new_width, new_height, TRUE);
  366.  
  367.   /*  Add an alpha channel  */
  368.   scale_region (&srcPR, &destPR);
  369.  
  370.   /*  Push the channel on the undo stack  */
  371.   undo_push_channel_mod (GIMP_DRAWABLE (channel)->gimage, channel);
  372.  
  373.   /*  Configure the new channel  */
  374.   GIMP_DRAWABLE (channel)->tiles = new_tiles;
  375.   GIMP_DRAWABLE (channel)->width = new_width;
  376.   GIMP_DRAWABLE (channel)->height = new_height;
  377.  
  378.   /*  bounds are now unknown  */
  379.   channel->bounds_known = FALSE;
  380.  
  381.   /*  Update the new channel position  */
  382.   drawable_update (GIMP_DRAWABLE (channel),
  383.            0, 0,
  384.            GIMP_DRAWABLE (channel)->width,
  385.            GIMP_DRAWABLE (channel)->height);
  386. }
  387.  
  388. void
  389. channel_resize (Channel *channel,
  390.         gint     new_width,
  391.         gint     new_height,
  392.         gint     offx,
  393.         gint     offy)
  394. {
  395.   PixelRegion srcPR, destPR;
  396.   TileManager *new_tiles;
  397.   guchar bg = 0;
  398.   gint clear;
  399.   gint w, h;
  400.   gint x1, y1, x2, y2;
  401.  
  402.   if (!new_width || !new_height)
  403.     return;
  404.  
  405.   x1 = CLAMP (offx, 0, new_width);
  406.   y1 = CLAMP (offy, 0, new_height);
  407.   x2 = CLAMP ((offx + GIMP_DRAWABLE (channel)->width), 0, new_width);
  408.   y2 = CLAMP ((offy + GIMP_DRAWABLE (channel)->height), 0, new_height);
  409.   w = x2 - x1;
  410.   h = y2 - y1;
  411.  
  412.   if (offx > 0)
  413.     {
  414.       x1 = 0;
  415.       x2 = offx;
  416.     }
  417.   else
  418.     {
  419.       x1 = -offx;
  420.       x2 = 0;
  421.     }
  422.  
  423.   if (offy > 0)
  424.     {
  425.       y1 = 0;
  426.       y2 = offy;
  427.     }
  428.   else
  429.     {
  430.       y1 = -offy;
  431.       y2 = 0;
  432.     }
  433.  
  434.   /*  Update the old channel position  */
  435.   drawable_update (GIMP_DRAWABLE (channel),
  436.            0, 0,
  437.            GIMP_DRAWABLE (channel)->width,
  438.            GIMP_DRAWABLE (channel)->height);
  439.  
  440.   /*  Configure the pixel regions  */
  441.   pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
  442.              x1, y1, w, h, FALSE);
  443.  
  444.   /*  Determine whether the new channel needs to be initially cleared  */
  445.   if ((new_width  > GIMP_DRAWABLE (channel)->width) ||
  446.       (new_height > GIMP_DRAWABLE (channel)->height) ||
  447.       (x2 || y2))
  448.     clear = TRUE;
  449.   else
  450.     clear = FALSE;
  451.  
  452.   /*  Allocate the new channel, configure dest region  */
  453.   new_tiles = tile_manager_new (new_width, new_height, 1);
  454.  
  455.   /*  Set to black (empty--for selections)  */
  456.   if (clear)
  457.     {
  458.       pixel_region_init (&destPR, new_tiles, 0, 0, new_width, new_height, TRUE);
  459.       color_region (&destPR, &bg);
  460.     }
  461.  
  462.   /*  copy from the old to the new  */
  463.   pixel_region_init (&destPR, new_tiles, x2, y2, w, h, TRUE);
  464.   if (w && h)
  465.     copy_region (&srcPR, &destPR);
  466.  
  467.   /*  Push the channel on the undo stack  */
  468.   undo_push_channel_mod (GIMP_DRAWABLE (channel)->gimage, channel);
  469.  
  470.   /*  Configure the new channel  */
  471.   GIMP_DRAWABLE (channel)->tiles  = new_tiles;
  472.   GIMP_DRAWABLE (channel)->width  = new_width;
  473.   GIMP_DRAWABLE (channel)->height = new_height;
  474.  
  475.   /*  bounds are now unknown  */
  476.   channel->bounds_known = FALSE;
  477.  
  478.   /*  update the new channel area  */
  479.   drawable_update (GIMP_DRAWABLE (channel),
  480.            0, 0,
  481.            GIMP_DRAWABLE (channel)->width,
  482.            GIMP_DRAWABLE (channel)->height);
  483. }
  484.  
  485. void            
  486. channel_update (Channel *channel)
  487. {
  488.   drawable_update (GIMP_DRAWABLE (channel),
  489.            0, 0,
  490.            GIMP_DRAWABLE (channel)->width,
  491.            GIMP_DRAWABLE (channel)->height);
  492.   gdisplays_flush ();
  493. }
  494.  
  495. /**********************/
  496. /*  access functions  */
  497. /**********************/
  498.  
  499. gboolean
  500. channel_toggle_visibility (Channel *channel)
  501. {
  502.   GIMP_DRAWABLE (channel)->visible = !GIMP_DRAWABLE (channel)->visible;
  503.  
  504.   return GIMP_DRAWABLE (channel)->visible;
  505. }
  506.  
  507. TempBuf *
  508. channel_preview (Channel *channel,
  509.          gint     width,
  510.          gint     height)
  511. {
  512.   /* Ok prime the cache with a large preview if the cache is invalid */
  513.   if (! GIMP_DRAWABLE (channel)->preview_valid &&
  514.       width  <= PREVIEW_CACHE_PRIME_WIDTH    &&
  515.       height <= PREVIEW_CACHE_PRIME_HEIGHT   &&
  516.       GIMP_DRAWABLE (channel)->gimage          &&
  517.       GIMP_DRAWABLE (channel)->gimage->width  > PREVIEW_CACHE_PRIME_WIDTH   &&
  518.       GIMP_DRAWABLE (channel)->gimage->height > PREVIEW_CACHE_PRIME_HEIGHT)
  519.     {
  520.       TempBuf * tb = channel_preview_private (channel,
  521.                           PREVIEW_CACHE_PRIME_WIDTH,
  522.                           PREVIEW_CACHE_PRIME_HEIGHT);
  523.       
  524.       /* Save the 2nd call */
  525.       if (width  == PREVIEW_CACHE_PRIME_WIDTH &&
  526.       height == PREVIEW_CACHE_PRIME_HEIGHT)
  527.     return tb;
  528.     }
  529.  
  530.   /* Second call - should NOT visit the tile cache...*/
  531.   return channel_preview_private (channel, width, height);
  532. }
  533.  
  534. static TempBuf *
  535. channel_preview_private (Channel *channel,
  536.              gint     width,
  537.              gint     height)
  538. {
  539.   MaskBuf     *preview_buf;
  540.   PixelRegion  srcPR;
  541.   PixelRegion  destPR;
  542.   gint         subsample;
  543.   TempBuf     *ret_buf;
  544.  
  545.   g_return_val_if_fail (channel != NULL, NULL);
  546.   g_return_val_if_fail (GIMP_IS_CHANNEL (channel), NULL);
  547.   
  548.   /*  The easy way  */
  549.   if (GIMP_DRAWABLE (channel)->preview_valid &&
  550.       (ret_buf =
  551.        gimp_preview_cache_get (& (GIMP_DRAWABLE (channel)->preview_cache),
  552.                    width, height)))
  553.     return ret_buf;
  554.   /*  The hard way  */
  555.   else
  556.     {
  557.       /*  calculate 'acceptable' subsample  */
  558.       subsample = 1;
  559.       if (width < 1) width = 1;
  560.       if (height < 1) height = 1;
  561.       while ((width  * (subsample + 1) * 2 < GIMP_DRAWABLE (channel)->width) &&
  562.          (height * (subsample + 1) * 2 < GIMP_DRAWABLE (channel)->height))
  563.     subsample = subsample + 1;
  564.  
  565.       pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
  566.              0, 0,
  567.              GIMP_DRAWABLE (channel)->width,
  568.              GIMP_DRAWABLE (channel)->height, FALSE);
  569.  
  570.       preview_buf = mask_buf_new (width, height);
  571.       destPR.bytes     = 1;
  572.       destPR.x         = 0;
  573.       destPR.y         = 0;
  574.       destPR.w         = width;
  575.       destPR.h         = height;
  576.       destPR.rowstride = width;
  577.       destPR.data      = mask_buf_data (preview_buf);
  578.  
  579.       subsample_region (&srcPR, &destPR, subsample);
  580.  
  581.       if (!GIMP_DRAWABLE (channel)->preview_valid)
  582.     gimp_preview_cache_invalidate (&(GIMP_DRAWABLE(channel)->preview_cache));
  583.  
  584.       GIMP_DRAWABLE (channel)->preview_valid = TRUE;
  585.       gimp_preview_cache_add (&(GIMP_DRAWABLE (channel)->preview_cache),
  586.                   preview_buf);
  587.       return preview_buf;
  588.     }
  589. }
  590.  
  591. void
  592. channel_invalidate_previews (GimpImage* gimage)
  593. {
  594.   GSList * tmp;
  595.   Channel * channel;
  596.  
  597.   g_return_if_fail (gimage != NULL);
  598.  
  599.   tmp = gimage->channels;
  600.  
  601.   while (tmp)
  602.     {
  603.       channel = (Channel *) tmp->data;
  604.       gimp_drawable_invalidate_preview (GIMP_DRAWABLE (channel), TRUE);
  605.       tmp = g_slist_next (tmp);
  606.     }
  607. }
  608.  
  609. Tattoo
  610. channel_get_tattoo (const Channel *channel)
  611. {
  612.   return (gimp_drawable_get_tattoo (GIMP_DRAWABLE (channel)));
  613. }
  614.  
  615. void
  616. channel_set_tattoo (const Channel *channel, 
  617.             Tattoo         value)
  618. {
  619.   gimp_drawable_set_tattoo (GIMP_DRAWABLE (channel), value);
  620. }
  621.  
  622. /******************************/
  623. /*  selection mask functions  */
  624. /******************************/
  625.  
  626. Channel *
  627. channel_new_mask (GimpImage *gimage,
  628.           gint       width,
  629.           gint       height)
  630. {
  631.   guchar black[3] = {0, 0, 0};
  632.   Channel *new_channel;
  633.  
  634.   /*  Create the new channel  */
  635.   new_channel = channel_new (gimage, width, height,
  636.                  _("Selection Mask"), 127, black);
  637.  
  638.   /*  Set the validate procedure  */
  639.   tile_manager_set_validate_proc (GIMP_DRAWABLE (new_channel)->tiles,
  640.                   channel_validate);
  641.  
  642.   return new_channel;
  643. }
  644.  
  645. gboolean
  646. channel_boundary (Channel   *mask,
  647.           BoundSeg **segs_in,
  648.           BoundSeg **segs_out,
  649.           gint      *num_segs_in,
  650.           gint      *num_segs_out,
  651.           gint       x1,
  652.           gint       y1,
  653.           gint       x2,
  654.           gint       y2)
  655. {
  656.   gint x3, y3, x4, y4;
  657.   PixelRegion bPR;
  658.  
  659.   if (! mask->boundary_known)
  660.     {
  661.       /* free the out of date boundary segments */
  662.       if (mask->segs_in)
  663.     g_free (mask->segs_in);
  664.       if (mask->segs_out)
  665.     g_free (mask->segs_out);
  666.  
  667.       if (channel_bounds (mask, &x3, &y3, &x4, &y4))
  668.     {
  669.       pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles,
  670.                  x3, y3, (x4 - x3), (y4 - y3), FALSE);
  671.       mask->segs_out = find_mask_boundary (&bPR, &mask->num_segs_out,
  672.                            IgnoreBounds,
  673.                            x1, y1,
  674.                            x2, y2);
  675.       x1 = MAX (x1, x3);
  676.       y1 = MAX (y1, y3);
  677.       x2 = MIN (x2, x4);
  678.       y2 = MIN (y2, y4);
  679.  
  680.       if (x2 > x1 && y2 > y1)
  681.         {
  682.           pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles,
  683.                  0, 0,
  684.                  GIMP_DRAWABLE (mask)->width,
  685.                  GIMP_DRAWABLE (mask)->height, FALSE);
  686.           mask->segs_in =  find_mask_boundary (&bPR, &mask->num_segs_in,
  687.                            WithinBounds,
  688.                            x1, y1,
  689.                            x2, y2);
  690.         }
  691.       else
  692.         {
  693.           mask->segs_in     = NULL;
  694.           mask->num_segs_in = 0;
  695.         }
  696.     }
  697.       else
  698.     {
  699.       mask->segs_in      = NULL;
  700.       mask->segs_out     = NULL;
  701.       mask->num_segs_in  = 0;
  702.       mask->num_segs_out = 0;
  703.     }
  704.       mask->boundary_known = TRUE;
  705.     }
  706.  
  707.   *segs_in      = mask->segs_in;
  708.   *segs_out     = mask->segs_out;
  709.   *num_segs_in  = mask->num_segs_in;
  710.   *num_segs_out = mask->num_segs_out;
  711.  
  712.   return TRUE;
  713. }
  714.  
  715. gint
  716. channel_value (Channel *mask,
  717.            gint     x,
  718.            gint     y)
  719. {
  720.   Tile *tile;
  721.   gint val;
  722.  
  723.   /*  Some checks to cut back on unnecessary work  */
  724.   if (mask->bounds_known)
  725.     {
  726.       if (mask->empty)
  727.     return 0;
  728.       else if (x < mask->x1 || x >= mask->x2 || y < mask->y1 || y >= mask->y2)
  729.     return 0;
  730.     }
  731.   else
  732.     {
  733.       if (x < 0 || x >= GIMP_DRAWABLE (mask)->width ||
  734.       y < 0 || y >= GIMP_DRAWABLE (mask)->height)
  735.     return 0;
  736.     }
  737.  
  738.   tile = tile_manager_get_tile (GIMP_DRAWABLE (mask)->tiles, x, y, TRUE, FALSE);
  739.   val = *(guchar *) (tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT));
  740.   tile_release (tile, FALSE);
  741.  
  742.   return val;
  743. }
  744.  
  745. gboolean
  746. channel_bounds (Channel *mask,
  747.         gint    *x1,
  748.         gint    *y1,
  749.         gint    *x2,
  750.         gint    *y2)
  751. {
  752.   PixelRegion maskPR;
  753.   guchar *data, *data1;
  754.   gint x, y;
  755.   gint ex, ey;
  756.   gint tx1, tx2, ty1, ty2;
  757.   gint minx, maxx;
  758.   gpointer pr;
  759.  
  760.   /*  if the mask's bounds have already been reliably calculated...  */
  761.   if (mask->bounds_known)
  762.     {
  763.       *x1 = mask->x1;
  764.       *y1 = mask->y1;
  765.       *x2 = mask->x2;
  766.       *y2 = mask->y2;
  767.  
  768.       return !mask->empty;
  769.     }
  770.  
  771.   /*  go through and calculate the bounds  */
  772.   tx1 = GIMP_DRAWABLE (mask)->width;
  773.   ty1 = GIMP_DRAWABLE (mask)->height;
  774.   tx2 = 0;
  775.   ty2 = 0;
  776.  
  777.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  778.              0, 0,
  779.              GIMP_DRAWABLE (mask)->width,
  780.              GIMP_DRAWABLE (mask)->height, FALSE);
  781.   for (pr = pixel_regions_register (1, &maskPR);
  782.        pr != NULL;
  783.        pr = pixel_regions_process (pr))
  784.     {
  785.       data1 = data = maskPR.data;
  786.       ex = maskPR.x + maskPR.w;
  787.       ey = maskPR.y + maskPR.h;
  788.       /* only check the pixels if this tile is not fully within the currently
  789.      computed bounds */
  790.       if (maskPR.x < tx1 || ex > tx2 ||
  791.       maskPR.y < ty1 || ey > ty2)
  792.         {
  793.       /* Check upper left and lower right corners to see if we can
  794.          avoid checking the rest of the pixels in this tile */
  795.       if (data[0] && data[maskPR.rowstride*(maskPR.h - 1) + maskPR.w - 1])
  796.       {
  797.         if (maskPR.x < tx1)
  798.           tx1 = maskPR.x;
  799.         if (ex > tx2)
  800.           tx2 = ex;
  801.         if (maskPR.y < ty1)
  802.           ty1 = maskPR.y;
  803.         if (ey > ty2)
  804.           ty2 = ey;
  805.       }
  806.       else
  807.         for (y = maskPR.y; y < ey; y++, data1 += maskPR.rowstride)
  808.         {
  809.           for (x = maskPR.x, data = data1; x < ex; x++, data++)
  810.         if (*data)
  811.         {
  812.           minx = x;
  813.           maxx = x;
  814.           for (; x < ex; x++, data++)
  815.             if (*data)
  816.               maxx = x;
  817.           if (minx < tx1)
  818.             tx1 = minx;
  819.           if (maxx > tx2)
  820.             tx2 = maxx;
  821.           if (y < ty1)
  822.             ty1 = y;
  823.           if (y > ty2)
  824.             ty2 = y;
  825.           }
  826.         }
  827.     }
  828.     }
  829.  
  830.   tx2 = CLAMP (tx2 + 1, 0, GIMP_DRAWABLE (mask)->width);
  831.   ty2 = CLAMP (ty2 + 1, 0, GIMP_DRAWABLE (mask)->height);
  832.  
  833.   if (tx1 == GIMP_DRAWABLE (mask)->width && ty1 == GIMP_DRAWABLE (mask)->height)
  834.     {
  835.       mask->empty = TRUE;
  836.       mask->x1    = 0;
  837.       mask->y1    = 0;
  838.       mask->x2    = GIMP_DRAWABLE (mask)->width;
  839.       mask->y2    = GIMP_DRAWABLE (mask)->height;
  840.     }
  841.   else
  842.     {
  843.       mask->empty = FALSE;
  844.       mask->x1    = tx1;
  845.       mask->y1    = ty1;
  846.       mask->x2    = tx2;
  847.       mask->y2    = ty2;
  848.     }
  849.   mask->bounds_known = TRUE;
  850.  
  851.   *x1 = tx1;
  852.   *x2 = tx2;
  853.   *y1 = ty1;
  854.   *y2 = ty2;
  855.  
  856.   return !mask->empty;
  857. }
  858.  
  859. gboolean
  860. channel_is_empty (Channel *mask)
  861. {
  862.   PixelRegion maskPR;
  863.   guchar * data;
  864.   gint x, y;
  865.   gpointer pr;
  866.  
  867.   if (mask->bounds_known)
  868.     return mask->empty;
  869.  
  870.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  871.              0, 0,
  872.              GIMP_DRAWABLE (mask)->width,
  873.              GIMP_DRAWABLE (mask)->height, FALSE);
  874.   for (pr = pixel_regions_register (1, &maskPR);
  875.        pr != NULL;
  876.        pr = pixel_regions_process (pr))
  877.     {
  878.       /*  check if any pixel in the mask is non-zero  */
  879.       data = maskPR.data;
  880.       for (y = 0; y < maskPR.h; y++)
  881.     for (x = 0; x < maskPR.w; x++)
  882.       if (*data++)
  883.         {
  884.           pixel_regions_process_stop (pr);
  885.           return FALSE;
  886.         }
  887.     }
  888.  
  889.   /*  The mask is empty, meaning we can set the bounds as known  */
  890.   if (mask->segs_in)
  891.     g_free (mask->segs_in);
  892.   if (mask->segs_out)
  893.     g_free (mask->segs_out);
  894.  
  895.   mask->empty          = TRUE;
  896.   mask->segs_in        = NULL;
  897.   mask->segs_out       = NULL;
  898.   mask->num_segs_in    = 0;
  899.   mask->num_segs_out   = 0;
  900.   mask->bounds_known   = TRUE;
  901.   mask->boundary_known = TRUE;
  902.   mask->x1             = 0;
  903.   mask->y1             = 0;
  904.   mask->x2             = GIMP_DRAWABLE (mask)->width;
  905.   mask->y2             = GIMP_DRAWABLE (mask)->height;
  906.  
  907.   return TRUE;
  908. }
  909.  
  910. void
  911. channel_add_segment (Channel *mask,
  912.              gint     x,
  913.              gint     y,
  914.              gint     width,
  915.              gint     value)
  916. {
  917.   PixelRegion maskPR;
  918.   guchar *data;
  919.   gint val;
  920.   gint x2;
  921.   gpointer pr;
  922.  
  923.   /*  check horizontal extents...  */
  924.   x2 = x + width;
  925.   if (x2 < 0) x2 = 0;
  926.   if (x2 > GIMP_DRAWABLE (mask)->width) x2 = GIMP_DRAWABLE (mask)->width;
  927.   if (x < 0) x = 0;
  928.   if (x > GIMP_DRAWABLE (mask)->width) x = GIMP_DRAWABLE (mask)->width;
  929.   width = x2 - x;
  930.   if (!width) return;
  931.  
  932.   if (y < 0 || y > GIMP_DRAWABLE (mask)->height)
  933.     return;
  934.  
  935.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  936.              x, y, width, 1, TRUE);
  937.   for (pr = pixel_regions_register (1, &maskPR);
  938.        pr != NULL;
  939.        pr = pixel_regions_process (pr))
  940.     {
  941.       data = maskPR.data;
  942.       width = maskPR.w;
  943.       while (width--)
  944.     {
  945.       val = *data + value;
  946.       if (val > 255)
  947.         val = 255;
  948.       *data++ = val;
  949.     }
  950.     }
  951. }
  952.  
  953. void
  954. channel_sub_segment (Channel *mask,
  955.              gint     x,
  956.              gint     y,
  957.              gint     width,
  958.              gint     value)
  959. {
  960.   PixelRegion maskPR;
  961.   guchar *data;
  962.   gint val;
  963.   gint x2;
  964.   gpointer pr;
  965.  
  966.   /*  check horizontal extents...  */
  967.   x2 = x + width;
  968.   if (x2 < 0) x2 = 0;
  969.   if (x2 > GIMP_DRAWABLE (mask)->width) x2 = GIMP_DRAWABLE (mask)->width;
  970.   if (x < 0) x = 0;
  971.   if (x > GIMP_DRAWABLE (mask)->width) x = GIMP_DRAWABLE (mask)->width;
  972.   width = x2 - x;
  973.   if (!width) return;
  974.  
  975.   if (y < 0 || y > GIMP_DRAWABLE (mask)->height)
  976.     return;
  977.  
  978.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles, x, y, width, 1, TRUE);
  979.   for (pr = pixel_regions_register (1, &maskPR);
  980.        pr != NULL;
  981.        pr = pixel_regions_process (pr))
  982.     {
  983.       data = maskPR.data;
  984.       width = maskPR.w;
  985.       while (width--)
  986.     {
  987.       val = *data - value;
  988.       if (val < 0)
  989.         val = 0;
  990.       *data++ = val;
  991.     }
  992.     }
  993. }
  994.  
  995. void
  996. channel_combine_rect (Channel    *mask,
  997.               ChannelOps  op,
  998.               gint        x,
  999.               gint        y,
  1000.               gint        w,
  1001.               gint        h)
  1002. {
  1003.   gint x2, y2;
  1004.   PixelRegion maskPR;
  1005.   guchar color;
  1006.  
  1007.   y2 = y + h;
  1008.   x2 = x + w;
  1009.  
  1010.   x  = CLAMP (x,  0, GIMP_DRAWABLE (mask)->width);
  1011.   y  = CLAMP (y,  0, GIMP_DRAWABLE (mask)->height);
  1012.   x2 = CLAMP (x2, 0, GIMP_DRAWABLE (mask)->width);
  1013.   y2 = CLAMP (y2, 0, GIMP_DRAWABLE (mask)->height);
  1014.  
  1015.   if (x2 - x <= 0 || y2 - y <= 0)
  1016.     return;
  1017.  
  1018.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1019.              x, y, x2 - x, y2 - y, TRUE);
  1020.   if (op == ADD  || op == REPLACE)
  1021.     color = 255;
  1022.   else
  1023.     color = 0;
  1024.   color_region (&maskPR, &color);
  1025.  
  1026.   /*  Determine new boundary  */
  1027.   if (mask->bounds_known && (op == ADD) && !mask->empty)
  1028.     {
  1029.       if (x < mask->x1)
  1030.     mask->x1 = x;
  1031.       if (y < mask->y1)
  1032.     mask->y1 = y;
  1033.       if ((x + w) > mask->x2)
  1034.     mask->x2 = (x + w);
  1035.       if ((y + h) > mask->y2)
  1036.     mask->y2 = (y + h);
  1037.     }
  1038.   else if (op == REPLACE || mask->empty)
  1039.     {
  1040.       mask->empty = FALSE;
  1041.       mask->x1 = x;
  1042.       mask->y1 = y;
  1043.       mask->x2 = x + w;
  1044.       mask->y2 = y + h;
  1045.     }
  1046.   else
  1047.     mask->bounds_known = FALSE;
  1048.  
  1049.   mask->x1 = CLAMP (mask->x1, 0, GIMP_DRAWABLE (mask)->width);
  1050.   mask->y1 = CLAMP (mask->y1, 0, GIMP_DRAWABLE (mask)->height);
  1051.   mask->x2 = CLAMP (mask->x2, 0, GIMP_DRAWABLE (mask)->width);
  1052.   mask->y2 = CLAMP (mask->y2, 0, GIMP_DRAWABLE (mask)->height);
  1053. }
  1054.  
  1055. void
  1056. channel_combine_ellipse (Channel    *mask,
  1057.              ChannelOps  op,
  1058.              gint        x,
  1059.              gint        y,
  1060.              gint        w,
  1061.              gint        h,
  1062.              gboolean    antialias)
  1063. {
  1064.   gint i, j;
  1065.   gint x0, x1, x2;
  1066.   gint val, last;
  1067.   gfloat a_sqr, b_sqr, aob_sqr;
  1068.   gfloat w_sqr, h_sqr;
  1069.   gfloat y_sqr;
  1070.   gfloat t0, t1;
  1071.   gfloat r;
  1072.   gfloat cx, cy;
  1073.   gfloat rad;
  1074.   gfloat dist;
  1075.  
  1076.   if (!w || !h)
  1077.     return;
  1078.  
  1079.   a_sqr = (w * w / 4.0);
  1080.   b_sqr = (h * h / 4.0);
  1081.   aob_sqr = a_sqr / b_sqr;
  1082.  
  1083.   cx = x + w / 2.0;
  1084.   cy = y + h / 2.0;
  1085.  
  1086.   for (i = y; i < (y + h); i++)
  1087.     {
  1088.       if (i >= 0 && i < GIMP_DRAWABLE (mask)->height)
  1089.     {
  1090.       /*  Non-antialiased code  */
  1091.       if (!antialias)
  1092.         {
  1093.           y_sqr = (i + 0.5 - cy) * (i + 0.5 - cy);
  1094.           rad = sqrt (a_sqr - a_sqr * y_sqr / (double) b_sqr);
  1095.           x1 = ROUND (cx - rad);
  1096.           x2 = ROUND (cx + rad);
  1097.  
  1098.           switch (op)
  1099.         {
  1100.         case ADD: case REPLACE:
  1101.           channel_add_segment (mask, x1, i, (x2 - x1), 255);
  1102.           break;
  1103.         case SUB :
  1104.           channel_sub_segment (mask, x1, i, (x2 - x1), 255);
  1105.           break;
  1106.         default:
  1107.           g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
  1108.           break;
  1109.         }
  1110.         }
  1111.       /*  antialiasing  */
  1112.       else
  1113.         {
  1114.           x0 = x;
  1115.           last = 0;
  1116.           h_sqr = (i + 0.5 - cy) * (i + 0.5 - cy);
  1117.           for (j = x; j < (x + w); j++)
  1118.         {
  1119.           w_sqr = (j + 0.5 - cx) * (j + 0.5 - cx);
  1120.  
  1121.           if (h_sqr != 0)
  1122.             {
  1123.               t0 = w_sqr / h_sqr;
  1124.               t1 = a_sqr / (t0 + aob_sqr);
  1125.               r = sqrt (t1 + t0 * t1);
  1126.               rad = sqrt (w_sqr + h_sqr);
  1127.               dist = rad - r;
  1128.             }
  1129.           else
  1130.             dist = -1.0;
  1131.  
  1132.           if (dist < -0.5)
  1133.             val = 255;
  1134.           else if (dist < 0.5)
  1135.             val = (int) (255 * (1 - (dist + 0.5)));
  1136.           else
  1137.             val = 0;
  1138.           
  1139.           if (last != val && last)
  1140.             {
  1141.               switch (op)
  1142.             {
  1143.             case ADD: case REPLACE:
  1144.               channel_add_segment (mask, x0, i, j - x0, last);
  1145.               break;
  1146.             case SUB:
  1147.               channel_sub_segment (mask, x0, i, j - x0, last);
  1148.               break;
  1149.             default:
  1150.               g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
  1151.               break;
  1152.             }
  1153.             }
  1154.  
  1155.           if (last != val)
  1156.             {
  1157.               x0 = j;
  1158.               last = val;
  1159.               /* because we are symetric accross the y axis we can
  1160.              skip ahead a bit if we are inside the ellipse*/
  1161.               if (val == 255 && j < cx)
  1162.             j = cx + (cx - j) - 1;
  1163.             }
  1164.         }
  1165.  
  1166.           if (last)
  1167.         {
  1168.           if (op == ADD || op == REPLACE)
  1169.             channel_add_segment (mask, x0, i, j - x0, last);
  1170.           else if (op == SUB)
  1171.             channel_sub_segment (mask, x0, i, j - x0, last);
  1172.           else
  1173.             g_warning ("Only ADD, REPLACE and SUB are valid for channel_combine!");
  1174.         }
  1175.         }
  1176.  
  1177.     }
  1178.     }
  1179.  
  1180.   /*  Determine new boundary  */
  1181.   if (mask->bounds_known && (op == ADD) && !mask->empty)
  1182.     {
  1183.       if (x < mask->x1)
  1184.     mask->x1 = x;
  1185.       if (y < mask->y1)
  1186.     mask->y1 = y;
  1187.       if ((x + w) > mask->x2)
  1188.     mask->x2 = (x + w);
  1189.       if ((y + h) > mask->y2)
  1190.     mask->y2 = (y + h);
  1191.     }
  1192.   else if (op == REPLACE || mask->empty)
  1193.     {
  1194.       mask->empty = FALSE;
  1195.       mask->x1 = x;
  1196.       mask->y1 = y;
  1197.       mask->x2 = x + w;
  1198.       mask->y2 = y + h;
  1199.     }
  1200.   else
  1201.     mask->bounds_known = FALSE;
  1202.  
  1203.   mask->x1 = CLAMP (mask->x1, 0, GIMP_DRAWABLE (mask)->width);
  1204.   mask->y1 = CLAMP (mask->y1, 0, GIMP_DRAWABLE (mask)->height);
  1205.   mask->x2 = CLAMP (mask->x2, 0, GIMP_DRAWABLE (mask)->width);
  1206.   mask->y2 = CLAMP (mask->y2, 0, GIMP_DRAWABLE (mask)->height);
  1207. }
  1208.  
  1209. static void
  1210. channel_combine_sub_region_add (void        *unused,
  1211.                 PixelRegion *srcPR,
  1212.                 PixelRegion *destPR)
  1213. {
  1214.   guchar *src, *dest;
  1215.   gint x, y, val;
  1216.  
  1217.   src  = srcPR->data;
  1218.   dest = destPR->data;
  1219.  
  1220.   for (y = 0; y < srcPR->h; y++)
  1221.     {
  1222.       for (x = 0; x < srcPR->w; x++)
  1223.     {
  1224.       val = dest[x] + src[x];
  1225.       if (val > 255)
  1226.         dest[x] = 255;
  1227.       else
  1228.         dest[x] = val;
  1229.     }
  1230.       src  += srcPR->rowstride;
  1231.       dest += destPR->rowstride;
  1232.     }
  1233. }
  1234.  
  1235. static void
  1236. channel_combine_sub_region_sub (void        *unused,
  1237.                 PixelRegion *srcPR,
  1238.                 PixelRegion *destPR)
  1239. {
  1240.   guchar *src, *dest;
  1241.   gint x, y;
  1242.  
  1243.   src  = srcPR->data;
  1244.   dest = destPR->data;
  1245.  
  1246.   for (y = 0; y < srcPR->h; y++)
  1247.     {
  1248.       for (x = 0; x < srcPR->w; x++)
  1249.     {
  1250.       if (src[x] > dest[x])
  1251.         dest[x] = 0;
  1252.       else
  1253.         dest[x]-= src[x];
  1254.     }
  1255.       src  += srcPR->rowstride;
  1256.       dest += destPR->rowstride;
  1257.     }
  1258. }
  1259.  
  1260. static void
  1261. channel_combine_sub_region_intersect (void        *unused,
  1262.                       PixelRegion *srcPR,
  1263.                       PixelRegion *destPR)
  1264. {
  1265.   guchar *src, *dest;
  1266.   gint x, y;
  1267.  
  1268.   src  = srcPR->data;
  1269.   dest = destPR->data;
  1270.  
  1271.   for (y = 0; y < srcPR->h; y++)
  1272.     {
  1273.       for (x = 0; x < srcPR->w; x++)
  1274.     {
  1275.       dest[x] = MIN (dest[x], src[x]);
  1276.     }
  1277.       src  += srcPR->rowstride;
  1278.       dest += destPR->rowstride;
  1279.   }
  1280. }
  1281.  
  1282. void
  1283. channel_combine_mask (Channel    *mask,
  1284.               Channel    *add_on,
  1285.               ChannelOps  op,
  1286.               gint        off_x,
  1287.               gint        off_y)
  1288. {
  1289.   PixelRegion srcPR, destPR;
  1290.   gint x1, y1, x2, y2;
  1291.   gint w, h;
  1292.  
  1293.   x1 = CLAMP (off_x, 0, GIMP_DRAWABLE (mask)->width);
  1294.   y1 = CLAMP (off_y, 0, GIMP_DRAWABLE (mask)->height);
  1295.   x2 = CLAMP (off_x + GIMP_DRAWABLE (add_on)->width, 0,
  1296.           GIMP_DRAWABLE (mask)->width);
  1297.   y2 = CLAMP (off_y + GIMP_DRAWABLE (add_on)->height, 0,
  1298.           GIMP_DRAWABLE (mask)->height);
  1299.  
  1300.   w = (x2 - x1);
  1301.   h = (y2 - y1);
  1302.  
  1303.   pixel_region_init (&srcPR, GIMP_DRAWABLE (add_on)->tiles,
  1304.              (x1 - off_x), (y1 - off_y), w, h, FALSE);
  1305.   pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles, x1, y1, w, h, TRUE);
  1306.  
  1307.   switch (op)
  1308.     {
  1309.     case ADD: case REPLACE:
  1310.       pixel_regions_process_parallel ((p_func) channel_combine_sub_region_add,
  1311.                       NULL, 2, &srcPR, &destPR);
  1312.       break;
  1313.     case SUB:
  1314.       pixel_regions_process_parallel ((p_func) channel_combine_sub_region_sub,
  1315.                       NULL, 2, &srcPR, &destPR);
  1316.       break;
  1317.     case INTERSECT:
  1318.       pixel_regions_process_parallel ((p_func)
  1319.                       channel_combine_sub_region_intersect,
  1320.                       NULL, 2, &srcPR, &destPR);
  1321.       break;
  1322.     default:
  1323.       g_message ("Error: unknown opperation type in channel_combine_mask\n");
  1324.       break;
  1325.     }
  1326.   mask->bounds_known = FALSE;
  1327. }
  1328.  
  1329. void
  1330. channel_feather (Channel    *input,
  1331.          Channel    *output,
  1332.          gdouble     radius_x,
  1333.          gdouble     radius_y,
  1334.          ChannelOps  op,
  1335.          gint        off_x,
  1336.          gint        off_y)
  1337. {
  1338.   gint x1, y1, x2, y2;
  1339.   PixelRegion srcPR;
  1340.  
  1341.   x1 = CLAMP (off_x, 0, GIMP_DRAWABLE (output)->width);
  1342.   y1 = CLAMP (off_y, 0, GIMP_DRAWABLE (output)->height);
  1343.   x2 = CLAMP (off_x + GIMP_DRAWABLE (input)->width, 0,
  1344.           GIMP_DRAWABLE (output)->width);
  1345.   y2 = CLAMP (off_y + GIMP_DRAWABLE (input)->height, 0,
  1346.           GIMP_DRAWABLE (output)->height);
  1347.  
  1348.   pixel_region_init (&srcPR, GIMP_DRAWABLE (input)->tiles,
  1349.              (x1 - off_x), (y1 - off_y), (x2 - x1), (y2 - y1), FALSE);
  1350.   gaussian_blur_region (&srcPR, radius_x, radius_y);
  1351.  
  1352.   if (input != output) 
  1353.     channel_combine_mask (output, input, op, off_x, off_y);
  1354.  
  1355.   output->bounds_known = FALSE;
  1356. }
  1357.  
  1358. void
  1359. channel_push_undo (Channel *mask)
  1360. {
  1361.   gint x1, y1, x2, y2;
  1362.   MaskUndo *mask_undo;
  1363.   TileManager *undo_tiles;
  1364.   PixelRegion srcPR, destPR;
  1365.   GImage *gimage;
  1366.  
  1367.   mask_undo = g_new (MaskUndo, 1);
  1368.   if (channel_bounds (mask, &x1, &y1, &x2, &y2))
  1369.     {
  1370.       undo_tiles = tile_manager_new ((x2 - x1), (y2 - y1), 1);
  1371.       pixel_region_init (&srcPR, GIMP_DRAWABLE (mask)->tiles,
  1372.              x1, y1, (x2 - x1), (y2 - y1), FALSE);
  1373.       pixel_region_init (&destPR, undo_tiles, 0, 0, (x2 - x1), (y2 - y1), TRUE);
  1374.       copy_region (&srcPR, &destPR);
  1375.     }
  1376.   else
  1377.     undo_tiles = NULL;
  1378.  
  1379.   mask_undo->tiles = undo_tiles;
  1380.   mask_undo->x     = x1;
  1381.   mask_undo->y     = y1;
  1382.  
  1383.   /* push the undo buffer onto the undo stack */
  1384.   gimage = GIMP_DRAWABLE (mask)->gimage;
  1385.   undo_push_mask (gimage, mask_undo);
  1386.   gimage_mask_invalidate (gimage);
  1387.  
  1388.   /*  invalidate the preview  */
  1389.   GIMP_DRAWABLE (mask)->preview_valid = FALSE;
  1390. }
  1391.  
  1392. void
  1393. channel_clear (Channel *mask)
  1394. {
  1395.   PixelRegion maskPR;
  1396.   guchar bg = 0;
  1397.  
  1398.   /*  push the current channel onto the undo stack  */
  1399.   channel_push_undo (mask);
  1400.  
  1401.   if (mask->bounds_known && !mask->empty)
  1402.     {
  1403.       pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1404.              mask->x1, mask->y1,
  1405.              (mask->x2 - mask->x1), (mask->y2 - mask->y1), TRUE);
  1406.       color_region (&maskPR, &bg);
  1407.     }
  1408.   else
  1409.     {
  1410.       /*  clear the mask  */
  1411.       pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1412.              0, 0,
  1413.              GIMP_DRAWABLE (mask)->width,
  1414.              GIMP_DRAWABLE (mask)->height, TRUE);
  1415.       color_region (&maskPR, &bg);
  1416.     }
  1417.  
  1418.   /*  we know the bounds  */
  1419.   mask->bounds_known = TRUE;
  1420.   mask->empty        = TRUE;
  1421.   mask->x1           = 0;
  1422.   mask->y1           = 0;
  1423.   mask->x2           = GIMP_DRAWABLE (mask)->width;
  1424.   mask->y2           = GIMP_DRAWABLE (mask)->height;
  1425. }
  1426.  
  1427. void
  1428. channel_invert (Channel *mask)
  1429. {
  1430.   PixelRegion maskPR;
  1431.   GimpLut *lut;
  1432.  
  1433.   /*  push the current channel onto the undo stack  */
  1434.   channel_push_undo (mask);
  1435.  
  1436.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1437.              0, 0,
  1438.              GIMP_DRAWABLE (mask)->width,
  1439.              GIMP_DRAWABLE (mask)->height, TRUE);
  1440.   
  1441.   lut = invert_lut_new (1);
  1442.  
  1443.   pixel_regions_process_parallel ((p_func) gimp_lut_process_inline,
  1444.                   lut, 1, &maskPR);
  1445.   gimp_lut_free (lut);
  1446.   mask->bounds_known = FALSE;
  1447. }
  1448.  
  1449. void
  1450. channel_sharpen (Channel *mask)
  1451. {
  1452.   PixelRegion maskPR;
  1453.   GimpLut *lut;
  1454.  
  1455.   /*  push the current channel onto the undo stack  */
  1456.   channel_push_undo (mask);
  1457.  
  1458.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1459.              0, 0,
  1460.              GIMP_DRAWABLE (mask)->width,
  1461.              GIMP_DRAWABLE (mask)->height, TRUE);
  1462.   lut = threshold_lut_new (0.5, 1);
  1463.  
  1464.   pixel_regions_process_parallel ((p_func) gimp_lut_process_inline,
  1465.                   lut, 1, &maskPR);
  1466.   gimp_lut_free (lut);
  1467.  
  1468.   mask->bounds_known = FALSE;
  1469. }
  1470.  
  1471. void
  1472. channel_all (Channel *mask)
  1473. {
  1474.   PixelRegion maskPR;
  1475.   guchar bg = 255;
  1476.  
  1477.   /*  push the current channel onto the undo stack  */
  1478.   channel_push_undo (mask);
  1479.  
  1480.   /*  clear the mask  */
  1481.   pixel_region_init (&maskPR, GIMP_DRAWABLE (mask)->tiles,
  1482.              0, 0,
  1483.              GIMP_DRAWABLE (mask)->width,
  1484.              GIMP_DRAWABLE (mask)->height, TRUE);
  1485.   color_region (&maskPR, &bg);
  1486.  
  1487.   /*  we know the bounds  */
  1488.   mask->bounds_known = TRUE;
  1489.   mask->empty        = FALSE;
  1490.   mask->x1           = 0;
  1491.   mask->y1           = 0;
  1492.   mask->x2           = GIMP_DRAWABLE (mask)->width;
  1493.   mask->y2           = GIMP_DRAWABLE (mask)->height;
  1494. }
  1495.  
  1496. void
  1497. channel_border (Channel *mask,
  1498.         gint     radius_x,
  1499.         gint     radius_y)
  1500. {
  1501.   PixelRegion bPR;
  1502.   gint x1, y1, x2, y2;
  1503.  
  1504.   if (radius_x < 0 || radius_y < 0)
  1505.     return;
  1506.  
  1507.   if (! channel_bounds (mask, &x1, &y1, &x2, &y2))
  1508.     return;
  1509.   if (channel_is_empty (mask))
  1510.     return;
  1511.  
  1512.   if (x1 - radius_x < 0)
  1513.     x1 = 0;
  1514.   else
  1515.     x1 -= radius_x;
  1516.   if (x2 + radius_x > GIMP_DRAWABLE (mask)->width)
  1517.     x2 = GIMP_DRAWABLE (mask)->width;
  1518.   else
  1519.     x2 += radius_x;
  1520.  
  1521.   if (y1 - radius_y < 0)
  1522.     y1 = 0;
  1523.   else
  1524.     y1 -= radius_y;
  1525.   if (y2 + radius_y > GIMP_DRAWABLE (mask)->height)
  1526.     y2 = GIMP_DRAWABLE (mask)->height;
  1527.   else
  1528.     y2 += radius_y;
  1529.   /*  push the current channel onto the undo stack  */
  1530.   channel_push_undo (mask);
  1531.  
  1532.   pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles, x1, y1,
  1533.              (x2-x1), (y2-y1), TRUE);
  1534.  
  1535.   border_region (&bPR, radius_x, radius_y);
  1536.  
  1537.   mask->bounds_known = FALSE;
  1538. }
  1539.  
  1540. void
  1541. channel_grow (Channel *mask,
  1542.           gint     radius_x,
  1543.           gint     radius_y)
  1544. {
  1545.   PixelRegion bPR;
  1546.   gint x1, y1, x2, y2;
  1547.  
  1548.   if (radius_x == 0 && radius_y == 0)
  1549.     return;
  1550.  
  1551.   if (radius_x <= 0 && radius_y <= 0)
  1552.     {
  1553.       channel_shrink (mask, -radius_x, -radius_y, FALSE);
  1554.       return;
  1555.     }
  1556.  
  1557.   if (radius_x < 0 || radius_y < 0)
  1558.     return;
  1559.   
  1560.   if (! channel_bounds (mask, &x1, &y1, &x2, &y2))
  1561.     return;
  1562.   if (channel_is_empty (mask))
  1563.     return;
  1564.  
  1565.   if (x1 - radius_x > 0)
  1566.     x1 = x1 - radius_x;
  1567.   else
  1568.     x1 = 0;
  1569.   if (y1 - radius_y > 0)
  1570.     y1 = y1 - radius_y;
  1571.   else
  1572.     y1 = 0;
  1573.   if (x2 + radius_x < GIMP_DRAWABLE (mask)->width)
  1574.     x2 = x2 + radius_x;
  1575.   else
  1576.     x2 = GIMP_DRAWABLE (mask)->width;
  1577.   if (y2 + radius_y < GIMP_DRAWABLE (mask)->height)
  1578.     y2 = y2 + radius_y;
  1579.   else
  1580.     y2 = GIMP_DRAWABLE (mask)->height;
  1581.  
  1582.   /*  push the current channel onto the undo stack  */
  1583.   channel_push_undo (mask);
  1584.  
  1585.   /*  need full extents for grow, not! */
  1586.   pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles, x1, y1, (x2 - x1),
  1587.              (y2 - y1), TRUE);
  1588.  
  1589.   fatten_region (&bPR, radius_x, radius_y);
  1590.  
  1591.   mask->bounds_known = FALSE;
  1592. }
  1593.  
  1594. void
  1595. channel_shrink (Channel  *mask,
  1596.         gint      radius_x,
  1597.         gint      radius_y,
  1598.         gboolean  edge_lock)
  1599. {
  1600.   PixelRegion bPR;
  1601.   gint x1, y1, x2, y2;
  1602.  
  1603.   if (radius_x == 0 && radius_y == 0)
  1604.     return;
  1605.  
  1606.   if (radius_x <= 0 && radius_y <= 0)
  1607.     {
  1608.       channel_grow (mask, -radius_x, -radius_y);
  1609.       return;
  1610.     }
  1611.  
  1612.   if (radius_x < 0 || radius_y < 0)
  1613.     return;
  1614.   
  1615.   if (! channel_bounds (mask, &x1, &y1, &x2, &y2))
  1616.     return;
  1617.   if (channel_is_empty (mask))
  1618.     return;
  1619.  
  1620.   if (x1 > 0)
  1621.     x1--;
  1622.   if (y1 > 0)
  1623.     y1--;
  1624.   if (x2 < GIMP_DRAWABLE (mask)->width)
  1625.     x2++;
  1626.   if (y2 < GIMP_DRAWABLE (mask)->height)
  1627.     y2++;
  1628.  
  1629.   /*  push the current channel onto the undo stack  */
  1630.   channel_push_undo (mask);
  1631.  
  1632.   pixel_region_init (&bPR, GIMP_DRAWABLE (mask)->tiles, x1, y1, (x2 - x1),
  1633.              (y2 - y1), TRUE);
  1634.  
  1635.   thin_region (&bPR, radius_x, radius_y, edge_lock);
  1636.  
  1637.   mask->bounds_known = FALSE;
  1638. }
  1639.  
  1640. void
  1641. channel_translate (Channel *mask,
  1642.            gint     off_x,
  1643.            gint     off_y)
  1644. {
  1645.   gint width, height;
  1646.   Channel *tmp_mask;
  1647.   PixelRegion srcPR, destPR;
  1648.   guchar empty = 0;
  1649.   gint   x1, y1, x2, y2;
  1650.  
  1651.   tmp_mask = NULL;
  1652.  
  1653.   /*  push the current channel onto the undo stack  */
  1654.   channel_push_undo (mask);
  1655.  
  1656.   channel_bounds (mask, &x1, &y1, &x2, &y2);
  1657.   x1 = CLAMP ((x1 + off_x), 0, GIMP_DRAWABLE (mask)->width);
  1658.   y1 = CLAMP ((y1 + off_y), 0, GIMP_DRAWABLE (mask)->height);
  1659.   x2 = CLAMP ((x2 + off_x), 0, GIMP_DRAWABLE (mask)->width);
  1660.   y2 = CLAMP ((y2 + off_y), 0, GIMP_DRAWABLE (mask)->height);
  1661.  
  1662.   width = x2 - x1;
  1663.   height = y2 - y1;
  1664.  
  1665.   /*  make sure width and height are non-zero  */
  1666.   if (width != 0 && height != 0)
  1667.     {
  1668.       /*  copy the portion of the mask we will keep to a
  1669.        *  temporary buffer
  1670.        */
  1671.       tmp_mask = channel_new_mask (GIMP_DRAWABLE (mask)->gimage, width, height);
  1672.  
  1673.       pixel_region_init (&srcPR, GIMP_DRAWABLE (mask)->tiles,
  1674.              x1 - off_x, y1 - off_y, width, height, FALSE);
  1675.       pixel_region_init (&destPR, GIMP_DRAWABLE (tmp_mask)->tiles,
  1676.              0, 0, width, height, TRUE);
  1677.       copy_region (&srcPR, &destPR);
  1678.     }
  1679.  
  1680.   /*  clear the mask  */
  1681.   pixel_region_init (&srcPR, GIMP_DRAWABLE (mask)->tiles,
  1682.              0, 0,
  1683.              GIMP_DRAWABLE (mask)->width,
  1684.              GIMP_DRAWABLE (mask)->height, TRUE);
  1685.   color_region (&srcPR, &empty);
  1686.  
  1687.   if (width != 0 && height != 0)
  1688.     {
  1689.       /*  copy the temp mask back to the mask  */
  1690.       pixel_region_init (&srcPR, GIMP_DRAWABLE (tmp_mask)->tiles,
  1691.              0, 0, width, height, FALSE);
  1692.       pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
  1693.              x1, y1, width, height, TRUE);
  1694.       copy_region (&srcPR, &destPR);
  1695.  
  1696.       /*  free the temporary mask  */
  1697.       channel_delete (tmp_mask);
  1698.     }
  1699.  
  1700.   /*  calculate new bounds  */
  1701.   if (width == 0 || height == 0)
  1702.     {
  1703.       mask->empty = TRUE;
  1704.       mask->x1 = 0; mask->y1 = 0;
  1705.       mask->x2 = GIMP_DRAWABLE (mask)->width;
  1706.       mask->y2 = GIMP_DRAWABLE (mask)->height;
  1707.     }
  1708.   else
  1709.     {
  1710.       mask->x1 = x1;
  1711.       mask->y1 = y1;
  1712.       mask->x2 = x2;
  1713.       mask->y2 = y2;
  1714.     }
  1715. }
  1716.  
  1717. void
  1718. channel_layer_alpha (Channel *mask,
  1719.              Layer   *layer)
  1720. {
  1721.   PixelRegion srcPR, destPR;
  1722.   guchar empty = 0;
  1723.   gint   x1, y1, x2, y2;
  1724.  
  1725.   /*  push the current mask onto the undo stack  */
  1726.   channel_push_undo (mask);
  1727.  
  1728.   /*  clear the mask  */
  1729.   pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
  1730.              0, 0,
  1731.              GIMP_DRAWABLE (mask)->width,
  1732.              GIMP_DRAWABLE (mask)->height, TRUE);
  1733.   color_region (&destPR, &empty);
  1734.  
  1735.   x1 = CLAMP (GIMP_DRAWABLE (layer)->offset_x, 0, GIMP_DRAWABLE (mask)->width);
  1736.   y1 = CLAMP (GIMP_DRAWABLE (layer)->offset_y, 0, GIMP_DRAWABLE (mask)->height);
  1737.   x2 = CLAMP (GIMP_DRAWABLE (layer)->offset_x + GIMP_DRAWABLE (layer)->width,
  1738.           0, GIMP_DRAWABLE (mask)->width);
  1739.   y2 = CLAMP (GIMP_DRAWABLE( layer)->offset_y + GIMP_DRAWABLE (layer)->height,
  1740.           0, GIMP_DRAWABLE (mask)->height);
  1741.  
  1742.   pixel_region_init (&srcPR, GIMP_DRAWABLE (layer)->tiles,
  1743.              (x1 - GIMP_DRAWABLE (layer)->offset_x),
  1744.              (y1 - GIMP_DRAWABLE (layer)->offset_y),
  1745.              (x2 - x1), (y2 - y1), FALSE);
  1746.   pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
  1747.              x1, y1, (x2 - x1), (y2 - y1), TRUE);
  1748.   extract_alpha_region (&srcPR, NULL, &destPR);
  1749.  
  1750.   mask->bounds_known = FALSE;
  1751. }
  1752.  
  1753. void
  1754. channel_load (Channel *mask,
  1755.           Channel *channel)
  1756. {
  1757.   PixelRegion srcPR, destPR;
  1758.  
  1759.   /*  push the current mask onto the undo stack  */
  1760.   channel_push_undo (mask);
  1761.  
  1762.   /*  copy the channel to the mask  */
  1763.   pixel_region_init (&srcPR, GIMP_DRAWABLE (channel)->tiles,
  1764.              0, 0,
  1765.              GIMP_DRAWABLE (channel)->width,
  1766.              GIMP_DRAWABLE (channel)->height, FALSE);
  1767.   pixel_region_init (&destPR, GIMP_DRAWABLE (mask)->tiles,
  1768.              0, 0,
  1769.              GIMP_DRAWABLE (channel)->width,
  1770.              GIMP_DRAWABLE (channel)->height, TRUE);
  1771.   copy_region (&srcPR, &destPR);
  1772.  
  1773.   mask->bounds_known = FALSE;
  1774. }
  1775.  
  1776. void
  1777. channel_invalidate_bounds (Channel *channel)
  1778. {
  1779.   channel->bounds_known = FALSE;
  1780. }
  1781.  
  1782.